package com.tang.calculator;

import com.tang.calculator.config.Formula;
import com.tang.calculator.config.FormulaConfigVO;
import com.tang.calculator.context.CalculateContext;
import com.tang.calculator.symbols.ValueSymbolHelper;
import com.tang.calculator.utils.JsonUtils;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * @auther: zhiy
 * @date: 2021/3/17
 * @description:
 */
@Slf4j
@Component
public class ConfigCalculator extends DefaultCalculator {

    public void executeConfig(String filePath, @NonNull String formType, @NonNull String operation, Map resource) throws Exception {


        //加载配置文件
        List<FormulaConfigVO> configVOList = JsonUtils.readJsonData(filePath, FormulaConfigVO.class);
        if (configVOList.size() < 1) throw new RuntimeException("解析失败，没有找到公式");
        for (FormulaConfigVO configVO : configVOList) {
            if (configVO.getProcession() != null && configVO.getProcession() != 0)
                ValueSymbolHelper.setPrecision(configVO.getProcession());
            try {
                if (formType.equals(configVO.getFormType()) && operation.equals(configVO.getOperation())) {
                    configVO.setResource(resource);
                    executeConfig(configVO);
                }
            } catch (Exception e) {
                throw e;
            } finally {
                ValueSymbolHelper.removePrecision();
            }
        }
    }

    public void executeConfig(FormulaConfigVO configVO) throws Exception {
        CalculateContext context = createContext();
        Map<String, Object> resource = configVO.getResource();
        List<Formula> formulas = configVO.getFormulas();
        context.setResource(resource);
        for (Formula formula : formulas) {
            String result = formula.getResult();
            String[] resultSplit = result.split("\\.");
            String clazzStr = resultSplit[0];
            String fieldStr = resultSplit[1];
            Object data = resource.get(clazzStr);
            context.setFormulaVO(formula);
            context.setFormula(formula.getFormula());
            if (data instanceof List) {
                List list = (List) data;
                for (Object o : list) {
                    context.setObj(o);
                    Field field = o.getClass().getDeclaredField(fieldStr);
                    field.setAccessible(true);
                    field.set(o, execute(context));
                }
            } else if (data instanceof Map) {
                context.setObj(data);
                ((Map) data).put(fieldStr, execute(context));
            } else {
                context.setObj(data);
                Field field = data.getClass().getDeclaredField(fieldStr);
                field.setAccessible(true);
                field.set(data, execute(context));
            }
        }
    }

    protected CalculateContext createContext() {
        return new CalculateContext();
    }
}
